home *** CD-ROM | disk | FTP | other *** search
- ;; Questions about this version to Jack Repenning <jackr@sgi.com>
- ;;
- ;; archie.el v2.0
- ;; A mock-interface to Archie for Emacs.
- ;;
- ;; -- original version by Brendan Kehoe (brendan@cs.widener.edu)
- ;; ange-ftp extensions by Sanjay Mathur (mathur@nas.nasa.gov)
- ;; ----- async support by Andy Norman (ange@hplb.hpl.hp.com)
- ;; ----- convert-to-dired by (drw@bourbaki.mit.edu)
- ;; ----- archie-server-preference-list by Jack Repenning (jackr@sgi.com)
- ;; ----- merge with original archie mode by Piet van Oostrum <piet@cs.ruu.nl>
- ;; ----- many enhancements thanks to the ange-ftp-lovers list
- ;; ----- further archie-mode functions, cleanup, by Rob Austein
- ;; ClearCase: archie.el@@/main/37
- ;; sites: /ftp@sgigate.sgi.com:/pub/archie-aux/archie.el
- ;; /ftp@alpha.gnu.ai.mit.edu:ange-ftp/archie.el
- ;;
- ;; This file is not part of GNU Emacs but the same permissions apply.
- ;;
- ;; GNU Emacs is free software; you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation; either version 1, or (at your option)
- ;; any later version.
- ;;
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;;
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs; see the file COPYING. If not, write to
- ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- ;;
- ;;
-
- ;; Usage:
- ;;
- ;; M-x archie creates a separate buffer from which you can find, copy
- ;; or run dired on any of the entries (using ange-ftp) and redo the search
- ;; with modified string and/or search-type.
- ;; alternatively M-x archie creates a separate buffer in dired mode (q.v).
-
- ;;
-
- ;; Installation instructions:
- ;;
- ;; Install this file as archie.el somewhere in your load-path and add the
- ;; following two lines to ~/.emacs. (without the semicolon's, of course)
- ;;
- ;; (autoload 'archie "archie" "Archie interface" t)
- ;;
- ;; You may have to change the value of archie-program and archie-server
- ;; as appropriate for your site.
- ;; archie-search-type and archie-download-directory can be modified
- ;; to suit personal preferences.
- ;;
- ;; For use with this package, it is also convenient to set
- ;; (setq ange-ftp-generate-anonymous-password t)
- ;;
- ;; Also, the crypt package (available in the LCD archives) is useful
- ;; with archie-find-file, since most archive sites store their files
- ;; in a compressed form.
-
- ;;
- ;; LCD Archive Entry:
- ;; archie|Sanjay R. Mathur|mathur@nas.nasa.gov
- ;; |A mock-interface to the archie program.
- ;; Wed Apr 22 22:31:46 1992|2.0||
- ;;
-
- ;; Customization variables
-
- (defvar archie-program "archie"
- "Program that queries archie servers.")
-
- (defvar archie-server-list
- '(("archie.funet.fi" . "128.214.6.100 (European server in Finland)")
- ("archie.rutgers.edu" . "128.6.18.15 (Rutgers University)")
- ("archie.sura.net" . "128.167.254.179 (SuraNet (Maryland, USA))")
- ("archie.unl.edu" . "129.93.1.14 (University of Nebraska in Lincoln)")
- ("archie.cs.huji.ac.il" . "132.65.6.15 (Israel server)")
- ("archie.au" . "139.130.4.6 (Australian server)")
- ("archie.doc.ic.ac.uk" . "146.169.11.3 (UK/England server)")
- ("archie.ans.net" . "147.225.1.2 (ANS archie server)")
- ("archie.ncu.edu.tw" . "140.115.19.24 (Taiwanese server)")
- ("archie.wide.ad.jp" . "133.4.3.6 (Japanese server)"))
- "List of known archie servers.")
-
- (defvar archie-server nil
- "*Server for \\[archie] searches. If ``nil'' (the default), asks.
- Known archie servers are listed in archie-server-list.")
-
- (defvar archie-download-directory nil
- "*Default directory into which any files copied by archie-copy are
- copied. nil means to use /usr/tmp.")
-
- (defvar archie-search-type "exact"
- "*Search type for \\[archie] searches. (Used to set command-line
- argument for archie program.) See also archie-search-type-sticky.
-
- Can be one of:
- exact for exact matches (-e) (default)
- regexp for a regexp (-r)
- substring for substring searches (-c)
- case-insensitive for a case-insensitive substring search (-s)
- exact-regexp for an exact regexp (-er)
- exact-substring for an exact substring search (-es)
- exact-case-insensitive for exact case-insensitive search (-ec)
- nil to ask every time")
-
- (defvar archie-search-type-sticky t
- "*Once you specify a search type, should it be made the new default
- (new value of archie-search-type)?")
-
- (defvar archie-search-type-alist
- ;; This is left as a defvar instead of defconst in case you don't like
- ;; the keyword choice here, eg, you want "substring" to mean
- ;; "case-insensitive-substring" (-s) as Allah clearly intended.
- '(("substring" . "-c")
- ("exact" . "-e")
- ("regexp" . "-r")
- ("case-insensitive" . "-s")
- ("exact-substring" . "-ec")
- ("exact-case-insensitive" . "-es")
- ("exact-regexp" . "-er"))
- "*Alist of search types for \\[archie] searches.")
-
- (defvar archie-internal-search-type-alist nil
- "Internal version of archie-search-type-alist (includes switches, as
- well as keywords).")
-
- (defun archie-search-type-alist ()
- "Returns value of archie-internal-search-type-alist, updating it if
- necessary."
- (if (eq archie-search-type-alist
- (nthcdr (length archie-search-type-alist)
- archie-internal-search-type-alist))
- archie-internal-search-type-alist
- (setq archie-internal-search-type-alist
- (nconc (mapcar (function (lambda (x) (cons (cdr x) (cdr x))))
- archie-search-type-alist)
- archie-search-type-alist))))
-
- (defvar archie-do-convert-to-dired nil
- "*If t archie buffers are converted to dired-mode, otherwise archie-mode
- is used.")
-
- (defvar archie-search-hits "1000"
- "*Maximum number of hits to ask for in search.")
-
- (defvar archie-window-management 'at-end
- "*When should \\[archie] display the window with the answer?
- 'at-start When the search is initiated
- 'at-end When the result is ready
- 'both Both
- otherwise Never")
-
- (defvar archie-server-preference-list nil
- "*List of regexps for ordering archie results by server. May be
- right-anchored with \"$\", e.g.:
- '(\"erlangen\\.de$\"
- \"tu-muenchen\\.de$\"
- \"\\.de$\")")
-
- (defvar archie-dired-unusable-functions
- (list
- ;; Classic dired functions
- 'dired-backup-unflag
- 'dired-byte-recompile
- 'dired-chgrp
- 'dired-chmod
- 'dired-chown
- 'dired-clean-directory
- 'dired-compress
- 'dired-do-deletions
- 'dired-flag-auto-save-files
- 'dired-flag-backup-files
- 'dired-flag-file-deleted
- 'dired-rename-file
- 'dired-uncompress
-
- ;;; Tree-dired functions
- 'dired-backup-diff
- ;; 'dired-backup-unflag
- 'dired-clean-directory
- ;; 'dired-create-directory
- ;; 'dired-diff
- 'dired-do-byte-compile
- 'dired-do-chgrp
- ;; 'dired-do-chmod
- 'dired-do-chown
- 'dired-do-compress
- ;; 'dired-do-copy
- ;; 'dired-do-copy-regexp
- 'dired-do-delete
- 'dired-do-flagged-delete
- 'dired-do-hardlink
- 'dired-do-hardlink-regexp
- ;; 'dired-do-kill
- 'dired-do-load
- ;; 'dired-do-move ; amounts to dired-do-copy
- 'dired-do-print
- ;; 'dired-do-redisplay
- 'dired-do-rename-regexp
- ;; 'dired-do-shell-command ; not likely the command knows what to
- ; do with such a name, but what the hey
- 'dired-do-symlink
- 'dired-do-symlink-regexp
- 'dired-do-uncompress
- 'dired-downcase
- ;; 'dired-find-file
- ;; 'dired-find-file-other-window
- 'dired-flag-auto-save-files
- 'dired-flag-backup-files
- 'dired-flag-file-deleted
- 'dired-flag-regexp-files
- 'dired-hide-all ; when ``i'' works ...
- 'dired-hide-subdir ; when ``i'' works ...
- ;; 'dired-kill-line-or-subdir
- ;; 'dired-mark-directories
- ;; 'dired-mark-executables
- ;; 'dired-mark-files-regexp
- ;; 'dired-mark-subdir-or-file
- ;; 'dired-mark-symlinks
- 'dired-maybe-insert-subdir
- ;; 'dired-next-dirline
- ;; 'dired-next-line
- ;; 'dired-next-marked-file
- ;; 'dired-next-subdir
- ;; 'dired-prev-dirline
- ;; 'dired-prev-marked-file
- ;; 'dired-prev-subdir
- ;; 'dired-previous-line
- ;; 'dired-quit
- 'dired-sort-toggle-or-edit
- ;; 'dired-summary
- ;; 'dired-tree-down
- ;; 'dired-tree-up
- ;; 'dired-undo
- ;; 'dired-unflag-all-files
- ;; 'dired-unmark-subdir-or-file
- ;; 'dired-up-directory
- 'dired-upcase
- ;; 'dired-view-file
- ;; 'dired-why
- ;; 'revert-buffer ; replaced with archie-modify-query
- )
- "*List of dired functions that should be removed from the
- archie-dired-mode keymap.")
-
- (defvar archie-mode-hook nil
- "Hooks to run after entering archie (non-dired) mode.")
-
- (defvar archie-dired-mode-hook nil
- "Hooks to run after entering archie-dired-mode.")
-
- (defvar archie-anonymous-ftp-username "anonymous"
- "Username to use for \"anonymous\" FTP connections.
- Set to \"anonymous\" by default, since more sites accept that than any
- other username (even \"ftp\", and no, not all machines in the world
- think they're synonyms). For dired-mode archie, this only matters for
- hosts where you've got a non-anonymous username set.")
-
- (defvar archie-display-hook nil
- "Hook run after displaying the results buffer.")
-
- (defvar archie-load-hook nil
- "Hooks run after loading archie.el")
-
-
- ;; Variables you shouldn't have to customize
-
- (defvar archie-l-output "[0-9]*Z *[0-9]* *\\([^ ]*\\) *\\(.*$\\)"
- "Regular expression matching the results of archie -l query. The
- two subexpressions match the host-name and the path respectively.")
-
- (defvar archie-last-query nil)
- (defvar archie-last-type nil)
-
- (defvar archie-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "f" 'archie-find-file)
- (define-key map "a" 'archie-modify-query)
- (define-key map "c" 'archie-copy)
- (define-key map "x" 'convert-archie-to-dired)
- (define-key map "d" 'archie-dired)
- (define-key map "v" 'archie-view-file)
- (define-key map "n" 'archie-next-line)
- (define-key map "s" 'archie-change-server)
- (define-key map " " 'archie-next-line)
- (define-key map "\C-n" 'archie-next-line)
- (define-key map "p" 'archie-previous-line)
- (define-key map "\C-?" 'archie-previous-line)
- (define-key map "\C-p" 'archie-previous-line)
- map)
- "Local keymap used when in archie (non-dired) mode.")
-
- (defvar archie-dired-mode-map nil
- "Local keymap used when in archie-dired-mode. Normally cloned from
- dired-mode-map, after dired-mode-hook is run.")
-
- (defun archie (type string)
- "Search (with style TYPE, or prompt if arg) for STRING on an Archie
- server.
-
- TYPE is the type of search to make -- by default, it's
- `archie-search-type'. Possible values are exact, substring (case
- sensitive), case-insensitive and regexp (a regular expression).
- Interactively, a prefix arg will make it prompt for this. If
- archie-search-type is NIL, always prompts. If
- archie-search-type-sticky is non-nil, each specified value is used as
- the next default; otherwise it reverts to archie-search-type.
-
- STRING is the string (or regexp) for which to search.
-
- If archie-do-convert-to-dired is non-NIL, the buffer is converted to a
- dired buffer.
-
- The total number of search hits will be limited to (approximately)
- archie-search-hits. If the prefix arg is >= 16 (e.g., ^U ^U
- \\[archie]), then you will be prompted for a new value for
- archie-search-hits."
- (interactive (archie-get-query-args archie-search-type nil))
- (let ((buf (generate-new-buffer string))
- (flags (concat (or (cdr (assoc type (archie-search-type-alist)))
- (cdr (assoc archie-search-type
- (archie-search-type-alist)))
- "-e"))))
- (save-window-excursion
- (set-buffer buf)
- (setq archie-last-query string)
- (setq archie-last-type type)
- (setq buffer-read-only nil)
- (erase-buffer)
- (archie-mode)
- (set
- (make-local-variable 'archie-msg)
- (message "Asking archie for %s match for \"%s\" ..." type string)))
- (if (or (eq archie-window-management 'at-start)
- (eq archie-window-management 'both))
- (progn
- (display-buffer buf)
- (run-hooks 'archie-display-hook)))
- (let ((proc (start-process "archie" ;name
- buf ;buffer
- archie-program ;program
- "-h" archie-server ;program args
- "-m" archie-search-hits
- flags "-l" "-"
- string)))
- (process-kill-without-query proc)
- (set-process-sentinel proc (function archie-process-sentinel)))))
-
- (defun archie-process-sentinel (proc string)
- (if (buffer-name (process-buffer proc))
- (unwind-protect
- (save-window-excursion
- (set-buffer (process-buffer proc))
- (let ((am archie-msg))
- (message "%s converting." am)
- (goto-char (point-min))
- (archie-order-results)
- (require 'ange-ftp)
- (if archie-do-convert-to-dired (convert-archie-to-dired))
- (setq buffer-read-only t)
- (message "%s done." am)))
- (if (or (eq archie-window-management 'at-end)
- (eq archie-window-management 'both))
- (progn
- (display-buffer (process-buffer proc))
- (run-hooks 'archie-display-hook))))))
-
- (defun archie-order-results ()
- "Order archie results by archie-server-preference-list."
- (goto-char (point-min))
- (mapcar
- (function
- (lambda (server-re)
- (let (match)
- (if (string-match "\\$$" server-re)
- (setq server-re
- (concat (substring server-re 0 -1) " ")))
- (while
- (save-excursion
- (re-search-forward (concat "^[0-9Z]+\\s +[0-9]+ \\S *"
- server-re
- ".*")
- nil t))
- (setq match (buffer-substring (match-beginning 0) (1+ (match-end 0))))
- (delete-region (match-beginning 0) (1+ (match-end 0)))
- (insert match)))))
- archie-server-preference-list))
-
- (defun convert-archie-to-dired ()
- "Convert a buffer containing output in 'archie -l' format into a Dired-mode
- buffer in which the usual Dired commands can be used, via ange-ftp."
- (interactive)
- (if (not (fboundp 'ange-ftp-get-user)) (load "ange-ftp"))
- (let (lines b s date size host file type year)
- (setq year (substring (current-time-string) -4))
- (setq lines (count-lines (point-min) (point-max)))
- (setq buffer-read-only nil)
- (goto-char (point-min))
- (insert " total " (int-to-string lines) ?\n)
- (while (not (eobp))
- (condition-case error
- (progn
- (setq b (point))
- (beginning-of-line 2)
- (setq s (buffer-substring b (point)))
- (or (string-match
- "^\\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\\)Z +\\([0-9]+\\) \\([-_.a-zA-Z0-9]+\\) \\([^ \n]+\\)$"
- s)
- (error "Line not from 'archie -l'"))
- (setq date (substring s (match-beginning 1) (match-end 1)))
- (setq size (substring s (match-beginning 2) (match-end 2)))
- (setq host (substring s (match-beginning 3) (match-end 3)))
- (setq file (substring s (match-beginning 4) (match-end 4)))
- (if (string-equal (substring file -1) "/")
- (setq file (substring file 0 -1)
- type "d")
- (setq type "-"))
- (save-excursion
- (insert " "
- ;; - or d, depending on whether it's a file or a directory
- type
- "r--r--r-- 1 ftp"
- ;; file size
- (make-string (- 8 (length size)) ? )
- size
- " "
- ;; creation date
- (condition-case error
- (aref
- ["Jan" "Feb" "Mar" "Apr" "May" "Jun"
- "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"]
- (1- (string-to-int (substring date 4 6))))
- (error "Jan"))
- " "
- (if (= (aref date 6) ?0)
- (concat " " (substring date 7 8))
- (substring date 6 8))
- (if (string-equal (substring date 0 4) year)
- (concat " " (substring date 8 10) ":" (substring date 10 12))
- (concat " " (substring date 0 4)))
- ;; file name, in Ange-FTP format
- (archie-get-user-prefix host) host ":" file
- ?\n))
- (delete-region b (point))
- (forward-line 1))
- (error (forward-line 1))))
- (archie-dired-mode)
- (goto-char (point-min))
- ;; Set subdir-alist so that Tree Dired will work:
- (if (fboundp 'dired-simple-subdir-alist)
- ;; will work even with nested dired format (dired-nstd.el,v 1.15
- ;; and later)
- (dired-simple-subdir-alist)
- ;; else we have an ancient tree dired (or classic dired, where
- ;; this does no harm)
- (set (make-local-variable 'dired-subdir-alist)
- (list (cons default-directory (point-min-marker)))))))
-
- (defun archie-get-user-prefix (host)
- "Return a suitable string to affix to the archie filename for this HOST."
- (if (not (fboundp 'ange-ftp-get-user)) (load "ange-ftp"))
- (let ((prefix (concat " /" archie-anonymous-ftp-username "@")))
- (if (or (not ange-ftp-default-user)
- (stringp ange-ftp-default-user))
- (let ((user (ange-ftp-get-user host)))
- (if (or (string-equal user "anonymous")
- (string-equal user "ftp"))
- (setq prefix " /"))))
- prefix))
-
- (defun archie-dired-mode ()
- "Mode for handling archie output as a dired buffer. Uses your own
- dired mode, as customized by any hooks. Also runs your own
- archie-dired-mode-hook, if any, and uses this modified keymap:
- \\{archie-dired-mode-map}."
- (if (not (fboundp 'dired-mode)) (load "dired"))
- (dired-mode (concat "archie " (buffer-name)))
- (setq default-directory "/usr/tmp/")
- (if archie-dired-mode-map
- nil
- (setq archie-dired-mode-map
- (copy-keymap (current-local-map)))
- (mapcar
- (function (lambda (fn)
- (substitute-key-definition fn nil archie-dired-mode-map)))
- archie-dired-unusable-functions)
- (substitute-key-definition 'revert-buffer
- 'archie-modify-query archie-dired-mode-map)
- (define-key archie-dired-mode-map "s" 'archie-change-server))
- (use-local-map archie-dired-mode-map)
- (setq major-mode 'archie-dired-mode)
- (setq mode-name "Archie Dired")
- (setq mode-line-buffer-indication '("Archie Dired: %17b"))
- (run-hooks 'archie-dired-mode-hook))
-
- (defun archie-get-filename ()
- (beginning-of-line)
- (if (looking-at archie-l-output)
- (concat "/" archie-anonymous-ftp-username "@"
- (buffer-substring (match-beginning 1) (match-end 1))
- ":"
- (buffer-substring (match-beginning 2) (match-end 2)))
- (error "Not archie -l output")))
-
- (defun archie-next-line (arg)
- (interactive "p")
- (next-line arg)
- (if (looking-at archie-l-output)
- (goto-char (match-beginning 1))))
-
- (defun archie-previous-line (arg)
- (interactive "p")
- (previous-line arg)
- (if (looking-at archie-l-output)
- (goto-char (match-beginning 1))))
-
- (defun archie-find-file ()
- "Find the file mentioned on the current line of archie -l output.
- Runs dired if the file is a directory and find-file-run-dired is
- non-nil."
- (interactive)
- (find-file (archie-get-filename)))
-
- (defun archie-view-file ()
- "View the file mentioned on the current line of archie -l output."
- (interactive)
- (view-file (archie-get-filename)))
-
- (defun archie-copy ()
- "Copy the file mentioned on the current line of archie -l output.
- Prompts with the value implied by archie-download-directory
- as the default directory in which to copy. The file-name part can be
- empty, in which case the original name is used."
- (interactive)
- (let* ((from (archie-get-filename))
- (from-nondir (file-name-nondirectory from))
- (to nil))
- (if (string-equal "" from-nondir)
- (error "%s is a directory" from))
- (setq to (read-file-name
- (format "Copy %s to: " from-nondir)
- (or archie-download-directory "/usr/tmp")))
- (if (file-directory-p to)
- (setq to (concat (file-name-as-directory to) from-nondir)))
- (copy-file from to 1)))
-
- (defun archie-dired ()
- "Run dired on the file or directory mentioned on the current line
- of archie -l output."
- (interactive)
- (dired (file-name-directory (archie-get-filename))))
-
- (defun archie-get-query-args (type-defl string-defl)
- "Queries user for search type (default: TYPE-DEFL) and string
- (default: STRING-DEFL). Use to prepare args for (interactive)."
- (let* ((tmp-type (or (if (or current-prefix-arg (null archie-search-type))
- (completing-read
- "Search type: "
- (archie-search-type-alist)
- nil
- t
- type-defl))
- archie-search-type))
- (tmp-string (read-string
- (concat "Ask Archie for " tmp-type " match for: ")
- string-defl)))
- (if archie-search-type-sticky
- (setq archie-search-type tmp-type))
- (if (and current-prefix-arg (<= 16 (car current-prefix-arg)))
- (let (tstr)
- (setq tstr (read-from-minibuffer "Reset archie-search-hits to: "))
- (while (>= 0 (string-to-int tstr))
- (setq tstr
- (read-from-minibuffer
- "Must be a number greater than zero. Reset archie-search-hits to: ")))
- (setq archie-search-hits tstr)))
- (list tmp-type tmp-string)))
-
- (defun archie-modify-query (type string)
- "Re-do the last archie search, with modification of the string
- and/or search type."
- (interactive (archie-get-query-args archie-last-type archie-last-query))
- (archie type string))
-
- (defun archie-server ()
- "Return current server, or prompt for new one."
- (interactive)
- (if archie-server
- archie-server
- (call-interactively 'archie-change-server)))
-
- (defun archie-change-server (new-server)
- "Change the current archie server to be NEW-SERVER."
- (interactive (list
- (completing-read
- (format "Change Archie server (current: %s): " archie-server)
- archie-server-list
- nil
- t)))
- (setq archie-server new-server))
-
- (defun archie-mode ()
- "Major mode for interacting with the archie program.
- Type: \\[archie-find-file] to find the file on the current line,
- or: \\[archie-copy] to copy it
- or: \\[archie-dired] to run dired.
- or: \\[convert-archie-to-dired] to convert the buffer to dired.
-
- To redo the last search with modification of the string and/or
- switches, type: \\[archie-modify-query].
-
- If archie-download-directory is set to non-nil then its value is used
- as the default directory while prompting for the target file by the
- archie-copy command; otherwise, /usr/tmp.
-
- \\{archie-mode-map}
-
- Runs archie-mode-hook, if defined."
- (kill-all-local-variables)
- (setq mode-name "Archie")
- (setq major-mode 'archie-mode)
- (use-local-map archie-mode-map)
- (setq mode-line-process '(": %s"))
- (run-hooks 'archie-mode-hook))
-
- (run-hooks 'archie-load-hook)
- (provide 'archie)
-